#pragma once

#include "SimpleEvent.h"
#include "SimpleCriticalSection.h"

namespace RoomFW {

//
// Class:	Thread
//
// Description:	Base thread class.  Provides the basic framwork for a thread.
//				Derived classes must implement specific functionality. 
//
// Author:	Andrew Sage
//
class Thread
{
public:

	//
	// Method:	Thread
	//
	// Description:	Constructor
	//
	// Parameters:	None
	//
	// Return:	None
	//
	Thread(void);

	//
	// Method:	~Thread
	//
	// Description:	Destructor
	//
	// Parameters:	None
	//
	// Return:	None
	//
	virtual ~Thread(void);

	//
	// Method:	start
	//
	// Description:	Start the thread.
	//
	// Parameters:
	//
	//	timeout - Time (milliseconds) to wait for thread to start.
	//
	//	priority - Windows thread priority.  Read MSDN for ::SetThreadPriority() and
	//				understand implications of change before passing non-default.
	//
	// Return:	True if the thread was successfully created.  Returns false if the
	//			thread is already running.
	//			If timeout other than INFINITE is passed, the caller should call
	//			isRunning to determine if the thread has actually started.
	//			Derived classes may override as necessary, but should call base to
	//			actually start the thread.
	//
	virtual bool start(uint32_t timeout, int priority);
	virtual bool start(uint32_t timeout = INFINITE) {return this->start(timeout, THREAD_PRIORITY_NORMAL);}

	//
	// Method:	stop
	//
	// Description:	Stop the thread.
	//
	// Parameters:
	//
	//	timeout - Time (milliseconds) to wait for thread to stop.
	//
	// Return:	True if the thread was successfully stoped.
	//			If timeout is not INFINITE, call isRunning to determine
	//			if the thread has actually stopped.  Derived classes
	//			may override as necessary, but should call base to
	//			actually stop the thread.
	//
	virtual bool stop(uint32_t timeout = INFINITE);

	//
	// Method:	wait
	//
	// Description:	Wait for the thread to stop.
	//
	// Parameters:
	//
	//	timeout - Time (milliseconds) to wait for thread to stop.
	//
	// Return:	True if the thread has stoped.
	//
	virtual bool wait(uint32_t timeout = INFINITE);

	//
	// Method:	isRunning
	//
	// Description:	Determine if the thread is running.  It is not
	//				considered running until the thread procedure
	//				has completed initialization and entered its
	//				wait and process loop.
	//
	// Parameters:
	//
	//	timeout - Time (milliseconds) to wait for thread to start.
	//
	// Return:	True if the thread is running.
	//
	virtual bool isRunning(uint32_t timeout = 0);

	//
	// Method:	getThreadPriority
	//
	// Description:	Get the thread priority.  See MSDN for ::GetThreadPriority(HANDLE).
	//				Only valid if this->isRunning().
	//
	// Parameters:	None.
	//
	// Return:	Thread priority.
	//
	int getThreadPriority();

	//
	// Method:	isErrored
	//
	// Description:	Determine if the thread is errored.  The thread
	//				is considered errored when it has caught an exception
	//				not handled by a derived class.
	//
	// Parameters:	None
	//
	// Return:	True if the thread is errored.
	//
	virtual bool isErrored();

	//
	// Method:	errorMessage
	//
	// Description:	Return the error message if isErrored() is true.
	//
	// Parameters:	None
	//
	// Return:	Error message.
	//
	virtual std::string errorMessage();

	//
	// Method:	getError
	//
	// Description:	Return the last IErrorSP caught.
	//
	// Parameters:	None
	//
	// Return:	The last IErrorSP caught.
	//
	virtual ErrorHandling::IErrorSP getError();

	//
	// Method:	getThreadName
	//
	// Description:	Get the thread name to show in the debugger.  Override to customize.
	//
	// Parameters:	None
	//
	// Return:	The thread name to show in the debugger.
	//
	virtual const char* getThreadName() const;

protected:

	//
	// Method:	initializeObject
	//
	// Description:	Called from start() to perform any one time
	//				initialization that could fail.  Derived class
	//				should override rather than doing anything that
	//				could fail in the constructor.  Called each time
	//				the thread is started, so just return true when
	//				already initialized.
	//
	// Parameters:	None
	//
	// Return:	Success
	//
	virtual bool initializeObject(void) { return true; }

	//
	// Method:	initializeThread
	//
	// Description:	Called from within the thread to perform any
	//				initialization required inside the thread before 
	//				it enters its wait and process loop.  Derived 
	//				class may override.
	//
	// Parameters:	None
	//
	// Return:	Success
	//
	virtual bool initializeThread(void) { return true; }

	//
	// Method:	main.
	//
	// Description:	Main thread procedure.  Derived classes must implement.
	//				When main() returns, the thread exits.
	//
	// Parameters:	None
	//
	// Return:	None
	//
	virtual void main(void) = 0;

	//
	// Method:	signalStop
	//
	// Description:	Called from the client/public interface
	//				to signal the thread to stop.  Derived
	//				classes must implement such that waitEvent()
	//				returns false.
	//
	// Parameters:	None
	//
	// Return:	None
	//
	virtual void signalStop(void) = 0;

	//
	// Method:	finalize
	//
	// Description:	Called from within the thread to perform any
	//				cleanup required after leaving its
	//				wait and process loop.  Derived class may
	//				override.
	//
	// Parameters:	None
	//
	// Return:	None
	//
	virtual void finalize(void) {}

	//
	// Method:	onStart
	//
	// Description:	Called from within the thread right before main.
	//
	// Parameters:	None
	//
	// Return:	None
	//
	virtual void onStart(void) {}

	//
	// Method:	onStop
	//
	// Description:	Called from within the thread right after main.
	//
	// Parameters:	None
	//
	// Return:	None
	//
	virtual void onStop(void) {}

private:

	//
	// Method:	ThreadProc
	//
	// Description:	Thread procedure.  Calls run().
	//
	// Parameters:
	//
	//	_this - Must be a pointer to a Thread object.
	//
	// Return:	None
	//
	static void ThreadProc(void* _this);

	//
	// Method:	run
	//
	// Description:	Main thread loop.  Initialize,
	//				wait and process, finalize.
	//
	// Parameters:	None
	//
	// Return:	None
	//
	void run(void);

	//
	// Method:	setError
	//
	// Description:	Set the thread in an error state.
	//
	// Parameters:
	//
	//	errorMessage - Error message.
	//
	// Return:	None
	//
	void setError(const char* errorMessage);

	//
	// Thread handle.
	//
	HANDLE handle_;

	//
	// Running event.  Signaled after thread initialization,
	// reset after thread finalization.  Do not modify handle
	// value by thread or when thread running.  Set/Reset ok.
	//
	SimpleEvent running_;

	//
	// Stopped event.  Needed to avoid infinite wait on running_.
	//
	SimpleEvent stopped_;

	//
	// Error tracking.
	//
	bool isErrored_;
	std::string errorMessage_;
	ErrorHandling::IErrorSP lastError_;
	SimpleCriticalSection errorGuard_;

	//
	// Not designed to be copied.  OS thread owned by one instance.
	//
	Thread(const Thread&);
	Thread& operator =(const Thread&);
};


//
// Class:	EventThread
//
// Description:	Framwork for an event driven thread.
//
// Author:	Andrew Sage
//
class EventThread : public virtual Thread
{
protected:
	//
	// Method:	waitEvent
	//
	// Description:	Called from within the thread to wait for an
	//				event.  Derived classes must implement.
	//
	// Parameters:	None
	//
	// Return:	Success
	//
	virtual bool waitEvent(void) = 0;

	//
	// Method:	handleEvent
	//
	// Description:	Called from within the thread to process
	//				an event.  Derived classes must implement.
	//				A false return exits the wait and process loop.
	//
	// Parameters:	None
	//
	// Return:	Success
	//
	virtual bool handleEvent(void) = 0;

	//
	// Method:	main
	//
	// Description:	Main thread loop.  Calls waitEvent() and handleEvent().
	//
	// Parameters:	None
	//
	// Return:	Success
	//
	virtual void main(void);
};

}
